home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Storage / Bento / FSHdr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  21.7 KB  |  754 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FSHdr.cpp
  3.  
  4.     Contains:    Class definition for ODFSBentoHandlers class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     9/27/96    EL        1353486: document may become write
  13.                                     protected after opening.
  14.          <6>     8/22/96    EL        1376276: flush after writing label.
  15.          <5>     8/21/96    EL        1376276: change fFileSize only if we are
  16.                                     appending.
  17.          <4>     8/19/96    DH        1376276:OpenDoc corrupts document when out
  18.                                     of disk space creating draft. Made numerous
  19.                                     exceptions fatal container errors. Also
  20.                                     changed calculation of disk space needed
  21.                                     for writes to include size of label.
  22.          <3>     5/24/96    jpa        1246074: Added missing CATCH_ALL's.
  23.          <2>     1/15/96    TJ        Cleaned Up
  24.         <17>     8/12/95    TÇ        1276806 Optimization: use kODFalse instead
  25.                                     of kODTrue in comparisons
  26.         <16>     5/26/95    VL        1251403: Multithreading naming support.
  27.         <15>     5/11/95    EL        Use ODBlockMove instead of memcpy.
  28.         <14>     4/25/95    EL        1242376: Synchronize label between handler
  29.                                     and container after WriteLabel.
  30.         <13>     4/10/95    EL        1236290: No debugger warning of file not
  31.                                     properly closed for DR2.
  32.         <12>      4/7/95    EL        1225905: More ModDate stuff to container.
  33.                                     Use FlipEnd.
  34.         <11>     3/24/95    EL        1225905: Move state information such as mod
  35.                                     date from plfmFile to here
  36.         <10>     3/13/95    EL        1226127 fix bug where endOfWrite is very
  37.                                     close to end of file we need a new block
  38.                                     for the safety label.
  39.          <9>     3/10/95    EL        1223465: allocate buffer on the heap.
  40.                                     1226127 fix bug buffering code destory
  41.                                     safety label at file end. Scan backward for
  42.                                     label if file is corrupted. 1227122
  43.                                     truncate file if space was lost in crash.
  44.          <8>     2/15/95    EL        1213321: Fix buffering bug where part of
  45.                                     the read in data is not the same as data in
  46.                                     a dirty buffer.
  47.          <7>     2/10/95    VL        1205627: Make it work for readonly file.
  48.          <6>     1/31/95    EL        1213321: Buffer the Bento file I/O.
  49.          <5>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  50.          <4>     8/26/94    EL        #1182308 Allows non-byte swapping
  51.                                     format/extract.
  52.          <3>      8/8/94    VL        1170009: Wrong byte calculation in
  53.                                     ReadHandler.
  54.          <2>     6/18/94    MB        Correct memory includes
  55.          <1>     5/27/94    VL        first checked in
  56.  
  57. */
  58.  
  59. #ifndef    _ODTYPES_
  60. #include "ODTypes.h"
  61. #endif
  62.  
  63. #ifndef _FSHDR_
  64. #include "FSHdr.h"
  65. #endif
  66.  
  67. #ifndef _BENTOHDR_
  68. #include "BentoHdr.h"
  69. #endif
  70.  
  71. #ifndef _SESSHDR_
  72. #include "SessHdr.h"
  73. #endif
  74.  
  75. #ifndef _EXCEPT_
  76. #include "Except.h"
  77. #endif
  78.  
  79. #ifndef _FLIPEND_
  80. #include "FlipEnd.h"
  81. #endif
  82.  
  83. #ifndef _PLFMFILE_
  84. #include "PlfmFile.h"
  85. #endif
  86.  
  87. #ifndef __CM_API__
  88. #include "CMAPI.h"
  89. #endif
  90.  
  91. #ifndef _ODMEMORY_
  92. #include "ODMemory.h"
  93. #endif
  94.  
  95. #ifndef _ERRORDEF_
  96. #include "ErrorDef.xh"
  97. #endif
  98.  
  99. #ifndef _BENTODEF_
  100. #include "BentoDef.h"
  101. #endif
  102.  
  103. //==============================================================================
  104. // Constants
  105. //==============================================================================
  106.  
  107. const ODType    kODBentoFileTypeName = "FileCtr";
  108.  
  109. #define kInvalidBuffer 1
  110. /* an invalid value for fBufferBegin */
  111.  
  112. #define MakeHighBitsMask(chunkSize)    ~((chunkSize) - 1)
  113. /* mask for masking off the lower bits */
  114.  
  115. //==============================================================================
  116. // Scalar Types
  117. //==============================================================================
  118.  
  119. //struct ContainerLabelFmt {            /* Layout of a container label:            */
  120. // unsigned char  magicBytes[8];        /* 8 bytes: the magic byte identifier    */
  121. // unsigned short flags;                /* 2    as a short                        */
  122. // unsigned short bufSize;            /* 2    TOC buffer size / 1024            */
  123. // unsigned short majorVersion;        /* 2    major format version number        */
  124. // unsigned short minorVersion;        /* 2    minor format version number        */
  125. // unsigned long    tocOffset;            /* 4    offset to start of TOC            */
  126. // unsigned long    tocSize;            /* 4    total byte size of the TOC        */
  127. //};
  128. //typedef struct ContainerLabelFmt ContainerLabelFmt;
  129.  
  130.  
  131. #pragma segment FSHdr
  132.  
  133. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  134. {
  135.     char    *dest = (char *)to + size - 1;
  136.     char    *src = (char *)from;
  137.     
  138.     while (size--)
  139.         *dest-- = *src++;            
  140. }
  141.  
  142.  
  143. extern void ODBentoFatalError(ODBoolean allowSuppress); // prototype
  144.  
  145. //==============================================================================
  146. // ODFSBentoHandlers
  147. //==============================================================================
  148.  
  149. ODFSBentoHandlers::ODFSBentoHandlers(CMSession session, PlatformFile* file)
  150. {
  151.     fFile = file;
  152.     fSession = session;
  153.     fBuffer = kODNULL;
  154.     fReverseEndian = kODFalse;        /* assume same Endian-ness                */
  155.     
  156.     fChunkSize = 0; // after setting, always calculate fChunkHighBitsMask 
  157.     fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  158. }
  159.  
  160. ODFSBentoHandlers::~ODFSBentoHandlers()
  161. {
  162. }
  163.  
  164. void ODFSBentoHandlers::Initialize()
  165. {
  166.     CMSetMetaHandler(fSession, kODBentoFileTypeName, (CMMetaHandler) containerMetahandler);
  167. }
  168.  
  169. CMSession ODFSBentoHandlers::GetCMSession()
  170. {
  171.     return fSession;
  172. }
  173.  
  174. CMRefCon ODFSBentoHandlers::OpenHandler(CMOpenMode mode)
  175. {
  176.     TRY
  177.     
  178.     ODULong    chunkSize;
  179.  
  180.     fFile->Open();
  181.     fFileSize = fFile->GetEndOfFile();
  182.     fPhysicalFileSize = fFileSize;    /* must set it here because used in read label */
  183.     fWriteLimit = fFileSize;        /* normally initialize in read label, but we may not have label */
  184.     fLogicalPos = 0;
  185.     fBufferBegin = kInvalidBuffer; /* buffer not loaded yet */
  186.     fBufferDirty = kODFalse;
  187.     fHasLabel = kODFalse;
  188.     chunkSize = fFile->GetAllocationBlockSize();
  189.     /* make sure it is a multiple of 2 */
  190.     for (fChunkSize = MininumChunkSize; fChunkSize < chunkSize; fChunkSize *= 2)
  191.         ;
  192.         
  193.     fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  194.     TRY
  195.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);
  196.     CATCH_ALL
  197.         /* there may be platform that returns a large chunksize to try to read     */
  198.         /* the whole file into memory. If that fails, we can try to allocate       */
  199.         /* with a default chunksize so that it can still run. In theory even       */
  200.         /* if the default chunksize memory allocation fails, we can still catch    */
  201.         /* and run without buffering, but if memory is really so short at        */
  202.         /* open time, may as well forget about it                                */
  203.         fChunkSize = DefaultChunkSize;
  204.         fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  205.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);    
  206.     ENDTRY
  207.     if ((strcmp(mode, "rb") == 0) || fFile->IsLocked())
  208.         fOpenReadOnly = kODTrue;
  209.     else {
  210.         fOpenReadOnly = kODFalse;
  211.         if (fFileSize > sizeof(ContainerLabelFmt)) {
  212.             CM_UCHAR magicBytes[8];
  213.             CMContainerFlags flags;
  214.             CM_USHORT bufSize;
  215.             CM_USHORT majorVersion;
  216.             CM_USHORT minorVersion;
  217.             ODULong tocOffset;
  218.             ODULong tocSize;
  219.             TRY
  220.                 this->ReadLabelHandler(magicBytes, &flags, &bufSize,
  221.                                          &majorVersion, &minorVersion,
  222.                                          &tocOffset, &tocSize);
  223.             CATCH_ALL
  224.             ENDTRY
  225.         }
  226.     }
  227.     CATCH_ALL
  228.     
  229.     WARN("error %ld error opening file container", (long) ErrorCode());
  230.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  231.     RERAISE;
  232.     
  233.     ENDTRY
  234.  
  235.     return ((CMRefCon) this);
  236. }
  237.  
  238. void ODFSBentoHandlers::CloseHandler()
  239. {
  240.     TRY
  241.     
  242.     if ( fBufferDirty )
  243.         this->FlushBuffer();
  244.     if ( !fOpenReadOnly ) {
  245.         fFile->SetEndOfFile(fFileSize);        /* remove the reserved space */
  246.     }
  247.         
  248.     fFile->Close();
  249.  
  250.     CATCH_ALL
  251.     // if file is locked, we can ignore the error
  252.     ODError err = ErrorCode(); ODVolatile(err);
  253.     if ( fBuffer ) {
  254.         ODDisposePtr(fBuffer);
  255.         fBuffer = kODNULL;
  256.     }
  257.     TRY
  258.     fFile->Close();
  259.     CATCH_ALL
  260.     ENDTRY
  261.  
  262.     WARN("error %ld error closing file container", (long) err);
  263.     if ((err > wPrErr) || (err < vLckdErr))
  264.     { 
  265.         ODBentoFatalError(/*allowSuppress*/ kODTrue);
  266.         RERAISE;
  267.     }
  268.         
  269.     ENDTRY
  270.  
  271.     if ( fBuffer ) {
  272.         ODDisposePtr(fBuffer);
  273.         fBuffer = kODNULL;
  274.     }
  275.     fHasLabel = kODFalse;
  276.  
  277. }
  278.  
  279. CMSize ODFSBentoHandlers::FlushHandler()
  280. {
  281.     int result = 0;
  282.     
  283.     ODVolatile(result);
  284.     
  285.     TRY    
  286.         if (fBufferDirty)
  287.             this->FlushBuffer();
  288.         fFile->FlushVolume();
  289.     CATCH_ALL
  290.         result = -1;
  291.  
  292.         WARN("error %ld error flushing file container", (long) ErrorCode());
  293.         ODBentoFatalError(/*allowSuppress*/ kODTrue);
  294.     ENDTRY
  295.     
  296.     return result;
  297. }
  298.  
  299. CMSize ODFSBentoHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  300. {
  301.     if (mode == kCMSeekEnd)
  302.         fLogicalPos = fFileSize + posOff;
  303.     else if (mode == kCMSeekCurrent) {
  304.         fLogicalPos = fLogicalPos + posOff;
  305.     }
  306.     else
  307.         fLogicalPos = posOff;
  308.     
  309.     return 0;
  310. }
  311.  
  312. CMSize ODFSBentoHandlers::TellHandler()
  313. {    
  314.     return fLogicalPos;
  315. }
  316.  
  317. CMSize ODFSBentoHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  318. {
  319.     ODULong    endOfRead, firstReadBlock, lastReadBlock;
  320.  
  321.     ODSLong amountRead = elementSize * theCount; ODVolatile(amountRead);
  322.  
  323.     TRY    
  324.  
  325.     endOfRead = fLogicalPos + amountRead;
  326.     if (endOfRead > fFileSize) {
  327.         amountRead = fFileSize - fLogicalPos;
  328.         endOfRead = fFileSize;
  329.     }
  330.  
  331.     firstReadBlock = fLogicalPos & fChunkHighBitsMask;
  332.     lastReadBlock = (endOfRead-1) & fChunkHighBitsMask;
  333.         
  334.     if (firstReadBlock == lastReadBlock) {
  335.         /* the content to read can be in a single buffer */
  336.         if (firstReadBlock != fBufferBegin) /* the block is not loaded */
  337.             this->ReloadBuffer();
  338.         /* After we make sure the buffer is loaded, we just copy it from the buffer */
  339.         ODBlockMove(fBuffer+fLogicalPos-fBufferBegin, buffer, amountRead);
  340.     }
  341.     else { /* for bigger block we read it directly bypassing the buffer */
  342.         /* if we read directly and part of data is in dirty buffer then write it first */
  343.         if ( fBufferDirty && (firstReadBlock <= fBufferBegin) && (fBufferBegin <= lastReadBlock))
  344.             this->FlushBuffer();
  345.         fFile->SetFilePos(fsFromStart, fLogicalPos);
  346.         fFile->Read((ODSByte*) buffer, &amountRead);
  347.     }
  348.     
  349.     fLogicalPos = endOfRead;
  350.     
  351.     CATCH_ALL
  352.     
  353.     WARN("error %ld error reading file container", (long) ErrorCode());
  354.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  355.     RERAISE;
  356.     
  357.     ENDTRY
  358.     
  359.     return ((CMSize)amountRead);
  360. }
  361.  
  362. CMSize ODFSBentoHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  363. {
  364.     ODSLong amountWritten = 0; ODVolatile(amountWritten);
  365.     
  366.     TRY
  367.     
  368.     if (theCount > 0) {    
  369.     
  370.         amountWritten = elementSize * theCount;
  371.         
  372.         // endOfWrite is the end of space for the write we must perform:
  373.         ODULong endOfWrite = fLogicalPos + amountWritten;
  374.         
  375.         // endOfNeed is the amount of total space we need, which includes the
  376.         // size of the label which must be included at end of file.  We must
  377.         // use this value to calculate the new end of file whenever the file
  378.         // must be made longer:
  379.         ODULong endOfNeed = endOfWrite;
  380.         if ( fHasLabel ) // we only need a label if we already have a label
  381.             endOfNeed += sizeof(ContainerLabelFmt);
  382.         
  383.         ODULong beginWriteBlock = fLogicalPos & fChunkHighBitsMask;
  384.         ODBoolean needToWrite = kODTrue;
  385.  
  386.         if ((beginWriteBlock == ((endOfWrite-1) & fChunkHighBitsMask)) && (beginWriteBlock != fBufferBegin)) {
  387.             /* changes are all in a single buffer but data not loaded, load it now */
  388.             this->ReloadBuffer();
  389.         }
  390.  
  391.         if (fBufferBegin != kInvalidBuffer) { /* we have a buffer */
  392.             if (fLogicalPos < fBufferBegin) { /* the tail of the write may touch the buffer */
  393.                 if (endOfWrite > fBufferBegin) { /* yes, the tail touches the buffer */
  394.                     /*
  395.                         fLogicalPos     fBufferBegin      endOfWrite
  396.                              |              |                 |       |
  397.                                             <-       ChunkSize      ->
  398.                                             <-  toMove      ->
  399.                     */
  400.                     ODULong toMove = endOfWrite - fBufferBegin;  /* move so many bytes into the buffer */
  401.                     if (toMove > fChunkSize)             /* but no larger than the buffer itself */
  402.                         toMove = fChunkSize;
  403.                     /* update the part of the buffer that has been changed */
  404.                     ODBlockMove((char *)buffer+fBufferBegin-fLogicalPos, fBuffer, toMove);
  405.                     /* note that we do not need to dirty it because we still write it out */
  406.                 }
  407.             }
  408.             else { /* the front part of the write may touch the buffer */
  409.                 ODULong theGap = fLogicalPos - fBufferBegin;
  410.                 if (theGap < fChunkSize) { /* yes, it does touch the buffer */
  411.                     /*
  412.                         fBufferBegin    fLogicalPos            endOfWrite
  413.                              |               |        |            |
  414.                              <-       ChunkSize      ->
  415.                              <-   theGap    ->
  416.                                              <-   amountWritten   ->
  417.                                              <-toMove->
  418.  
  419.                     */
  420.                     ODULong toMove = amountWritten;
  421.                     if (toMove + theGap > fChunkSize)
  422.                         toMove = fChunkSize - theGap;
  423.                     else {
  424.                         fBufferDirty = kODTrue; /* dirty it so we would write it out later */
  425.                         needToWrite = kODFalse;    /* for now, no writing is necessary */
  426.                     }
  427.                     ODBlockMove(buffer, fBuffer + theGap, toMove); /* update the buffer */
  428.                 }
  429.             }
  430.         }
  431.          
  432.         if (endOfNeed > fFileSize) { /* we don't have enough room */
  433.             if (endOfNeed > fWriteLimit) {
  434.                 /* extend it to block boundry */
  435.                 ODULong newEndOfFile = ((endOfNeed + fChunkSize)) & fChunkHighBitsMask;
  436.  
  437.                 ODSLong    newWriteLimit = newEndOfFile;
  438.                 if ( fHasLabel ) {
  439.                     newWriteLimit = newEndOfFile - sizeof(ContainerLabelFmt);
  440.                 }
  441.                 /* We will add at least another block to file, so we need a new label at end */
  442.                 fFile->SetEndOfFile(newEndOfFile);
  443.                 fPhysicalFileSize = newEndOfFile;
  444.                 fWriteLimit = newWriteLimit;
  445.                 if ( fHasLabel ) {
  446.                     if ((fWriteLimit & fChunkHighBitsMask) == fBufferBegin) {
  447.                         /* the label at the end will overlap with the buffer, put it in the buffer */
  448.                         ODBlockMove(&fLabel, fBuffer + fChunkSize - sizeof(ContainerLabelFmt), sizeof(ContainerLabelFmt));
  449.                     }
  450.                     fFile->SetFilePos(fsFromStart, fWriteLimit);
  451.                     TRY
  452.                         ODSLong labelSize = sizeof(ContainerLabelFmt);
  453.                         fFile->Write((const ODSByte*)&fLabel, &labelSize);
  454.                         /* if fails, no safety label at end of end, that is not end of the world */
  455.                         fFile->FlushVolume();
  456.                     CATCH_ALL
  457.                     ENDTRY
  458.                 }
  459.             }
  460.             if (endOfWrite > fFileSize) /* we are appending */
  461.                 fFileSize = endOfWrite;
  462.         }
  463.         if ( needToWrite ) {
  464.             fFile->SetFilePos(fsFromStart, fLogicalPos);
  465.             fFile->Write((const ODSByte*)buffer, &amountWritten);
  466.         }
  467.         fLogicalPos = endOfWrite;
  468.     }
  469.     CATCH_ALL
  470.     
  471.     ODError err = ErrorCode();
  472.     if ((err > wPrErr) || (err < vLckdErr))
  473.     { 
  474.         WARN("error %ld error writing file container", (long) err);
  475.         ODBentoFatalError(/*allowSuppress*/ kODTrue);
  476.     }
  477.     RERAISE;
  478.     
  479.     ENDTRY
  480.  
  481.     return ((CMSize)amountWritten);
  482. }
  483.  
  484. void ODFSBentoHandlers::FlushBuffer()
  485. {
  486.     ODSLong        theSize = fChunkSize;    
  487.  
  488.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  489.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  490.         theSize = fPhysicalFileSize - fBufferBegin;
  491.     fFile->Write(fBuffer, &theSize);
  492.     fBufferDirty = kODFalse;
  493. }
  494.  
  495. void ODFSBentoHandlers::ReloadBuffer()
  496. {
  497.     ODSLong        theSize;    
  498.  
  499.     if ( fBufferDirty )
  500.         this->FlushBuffer();
  501.     fBufferBegin = fLogicalPos & fChunkHighBitsMask;
  502.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  503.     theSize = fChunkSize;
  504.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  505.         theSize = fPhysicalFileSize - fBufferBegin;
  506.     fFile->Read(fBuffer, &theSize);
  507. }
  508.  
  509. CMEofStatus ODFSBentoHandlers::EOFHandler()
  510. {
  511.     return ((CMEofStatus) kODFalse);
  512.  
  513. }
  514.  
  515. CMBoolean ODFSBentoHandlers::TruncHandler(CMSize containerSize)
  516. {
  517.     fFileSize = containerSize;        
  518.     return kODTrue;
  519. }
  520.  
  521. CMSize ODFSBentoHandlers::ContainerSizeHandler()
  522. {
  523.     return ((CMSize) fFileSize);
  524. }
  525.  
  526. void ODFSBentoHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  527.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  528.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  529.                                      CMSize *tocOffset, CMSize *tocSize)
  530. {
  531.     TRY
  532.     
  533.     ODULong        endOfTOC, tempFileEnd;
  534.     char *magicSequence = "\xA4""CM""\xA5""Hdr""\xD7";        /* Must be 8 characters        */
  535.     ODBoolean         labelMatches = fHasLabel;
  536.  
  537.     /* Seek to the end of the label at the end of the container and read it...*/
  538.     
  539.     tempFileEnd = fFileSize;
  540.     while (tempFileEnd > sizeof(ContainerLabelFmt)) {
  541.         fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  542.         /* if we really want to speed it up, we could compare it directly from the buffer     */
  543.         /* but since we only need to loop through this in corrupted file and that does not    */
  544.         /* occur very often, and even when it happens, the current speed is acceptable          */
  545.         /* so we would leave it as it is now                                                */
  546.         if (this->ReadHandler((CMPtr)&fLabel, (CMSize)sizeof(unsigned char), 8) !=  8)
  547.                 THROW(kODErrBentoErr);
  548.         if (memcmp(&fLabel.magicBytes, magicSequence, 8) == 0)
  549.             labelMatches = kODTrue;
  550.         if (labelMatches) {
  551.             /* Return all the label info... */
  552.             fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  553.             if (this->ReadHandler((CMPtr)&fLabel, 
  554.                                   (CMSize)sizeof(unsigned char), 
  555.                                   sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  556.                     THROW(kODErrBentoErr);
  557.             ODBlockMove(&fLabel.magicBytes, magicByteSequence, 8);
  558. #if kCMDefaultEndian
  559.             /* little endian machine */
  560.             if ((fLabel.flags & kCMLittleEndianTwin) == 0) {
  561. #else
  562.             /* big endian machine */
  563.             if (fLabel.flags & kCMLittleEndianTwin) {
  564. #endif
  565.                 fReverseEndian = kODTrue;
  566.                 *flags = ODFlipShort(fLabel.flags);
  567.                 *bufSize = ODFlipShort(fLabel.bufSize);
  568.                 *majorVersion = ODFlipShort(fLabel.majorVersion);
  569.                 *minorVersion = ODFlipShort(fLabel.minorVersion);
  570.                 *tocOffset = ODFlipLong(fLabel.tocOffset);
  571.                 *tocSize = ODFlipLong(fLabel.tocSize);
  572.             }
  573.             else {
  574.                 fReverseEndian = kODFalse;
  575.                 *flags = (CMContainerFlags)fLabel.flags;
  576.                 *bufSize = (CM_USHORT)fLabel.bufSize;
  577.                 *majorVersion = (CM_USHORT)fLabel.majorVersion;
  578.                 *minorVersion = (CM_USHORT)fLabel.minorVersion;
  579.                 *tocOffset = (CMSize)fLabel.tocOffset;
  580.                 *tocSize = (CMSize)fLabel.tocSize;
  581.             }
  582.             endOfTOC = *tocOffset + *tocSize + sizeof(ContainerLabelFmt);
  583.             if (endOfTOC == tempFileEnd) {
  584.                 /* match exactly, this is most likely to be the label */
  585.                 if (endOfTOC != fFileSize) {
  586. #if ODDebug
  587.                     WARN("The file was corrupted! I will just do my best to read it");
  588. #endif
  589.                     fFileSize = endOfTOC;
  590.                 }
  591.                 fHasLabel = kODTrue;
  592.                 break;
  593.             }
  594.             if (endOfTOC < tempFileEnd) {
  595.                 ContainerLabelFmt tempLabel;
  596.                 fLogicalPos = endOfTOC - sizeof(ContainerLabelFmt);
  597.                 if (this->ReadHandler((CMPtr)&tempLabel, 
  598.                                       (CMSize)sizeof(unsigned char), 
  599.                                       sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  600.                     THROW(kODErrBentoErr);
  601.                 if (memcmp(&tempLabel, &fLabel, sizeof(ContainerLabelFmt)) == 0) {
  602. //#if ODDebug
  603. //                    WARN("The file was not closed properly! You get away with it this time");
  604. //#endif
  605.                     /* we passed the sanity check, so we can truncate the file and use the label */
  606.                     fFileSize = endOfTOC;
  607.                     fHasLabel = kODTrue;
  608.                     break;
  609.                 }
  610.                 /* even if we did not pass the test, if the label was at the end, still accept it */
  611.                 if (tempFileEnd == fFileSize) {
  612. #if ODDebug
  613.                     WARN("File looks funny! Send a copy to Bento folks");
  614. #endif
  615.                     fHasLabel = kODTrue;
  616.                     break;
  617.                 }
  618.             }
  619.         } /* it is a label */
  620.         /* otherwise keep scanning backwards */
  621.         labelMatches = kODFalse;
  622.         tempFileEnd -= 1;
  623.     }
  624.     if (fHasLabel) {
  625.         fPhysicalFileSize = fFileSize;
  626.         fWriteLimit = fFileSize;
  627.         if ( !fOpenReadOnly && (fFile->GetEndOfFile() != fFileSize)) {
  628.             fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  629.         }
  630.     }
  631. #if ODDebug
  632.     else
  633.         WARN("File has no valid Bento label. Cannot be recovered");
  634. #endif
  635.  
  636.     CATCH_ALL
  637.     
  638.     WARN("error %ld error reading file container label", (long) ErrorCode());
  639.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  640.     RERAISE;
  641.     
  642.     ENDTRY
  643. }
  644.  
  645. void ODFSBentoHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  646.                                         CMContainerFlags flags, CM_USHORT bufSize,
  647.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  648.                                         CMSize tocOffset, CMSize tocSize)
  649. {
  650.     TRY
  651.     
  652.     ContainerLabelFmt    theLabel;
  653.         
  654.     /* Fill in the label buffer with the info...                                                                                    */
  655.     
  656.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  657.     if (fReverseEndian) {
  658.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  659.         theLabel.bufSize = ODFlipShort(bufSize);
  660.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  661.         theLabel.minorVersion = ODFlipShort(minorVersion);
  662.         theLabel.tocOffset = ODFlipLong(tocOffset);
  663.         theLabel.tocSize = ODFlipLong(tocSize);
  664.     }
  665.     else {
  666.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  667.         theLabel.bufSize = (ODUShort)bufSize;
  668.         theLabel.majorVersion = (ODUShort)majorVersion; 
  669.         theLabel.minorVersion = (ODUShort)minorVersion;
  670.         theLabel.tocOffset = (ODULong)tocOffset;
  671.         theLabel.tocSize = (ODULong)tocSize;
  672.     }
  673.     
  674.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  675.  
  676.     /* Write the label to the end of the container value...                                                                */
  677.     
  678.     this->SeekHandler(0, kCMSeekEnd);
  679.     ODSLong labelSize = (unsigned long)this->WriteHandler((CMPtr)&theLabel,
  680.                                             (CMSize)sizeof(unsigned char),
  681.                                             (CMCount)sizeof(ContainerLabelFmt));
  682.     
  683.     if (labelSize != sizeof(ContainerLabelFmt))
  684.         THROW(kODErrBentoErr);
  685.  
  686.     this->FlushHandler();
  687.  
  688.     ODBlockMove(&theLabel, &fLabel, sizeof(ContainerLabelFmt));
  689.     fHasLabel = kODTrue;
  690.     fPhysicalFileSize = fFileSize;
  691.     fWriteLimit = fFileSize;
  692.     fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  693.  
  694.     CATCH_ALL
  695.     
  696.     WARN("error %ld error writing file container label", (long) ErrorCode());
  697.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  698.     RERAISE;
  699.     
  700.     ENDTRY
  701. }
  702.  
  703. CMValue ODFSBentoHandlers::ReturnParentValueHandler()
  704. {
  705.     return kODNULL;
  706. }
  707.  
  708. CM_UCHAR* ODFSBentoHandlers::ReturnContainerNameHandler()
  709. {
  710.     static Str63    name;
  711.     
  712.     fFile->GetAsciiName((char*)name,sizeof(name));
  713.     return ((CM_UCHAR *) name);
  714. }
  715.  
  716. CMType ODFSBentoHandlers::ReturnTargetTypeHandler(CMContainer container)
  717. {
  718. ODUnused(container);
  719.  
  720.     return kODNULL;
  721. }
  722.  
  723. void ODFSBentoHandlers::ExtractDataHandler(CMDataBuffer buffer,
  724.                                                  CMSize size, CMPrivateData data)
  725. {
  726.     ODBoolean    reverseEndian = fReverseEndian;
  727.     
  728.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  729.         size = -(CM_LONG)size;
  730.         reverseEndian = kODFalse;
  731.     }
  732.     
  733.     if (reverseEndian)
  734.         ODFlipMove(buffer, data, (size_t)size);
  735.     else
  736.         ODBlockMove(buffer, data, (size_t)size);
  737. }
  738.  
  739. void ODFSBentoHandlers::FormatDataHandler(CMDataBuffer buffer,
  740.                                      CMSize size, CMPrivateData data)
  741. {
  742.     ODBoolean    reverseEndian = fReverseEndian;
  743.     
  744.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  745.         size = -(CM_LONG)size;
  746.         reverseEndian = kODFalse;
  747.     }
  748.     
  749.     if (reverseEndian)
  750.         ODFlipMove(data, buffer, (size_t)size);
  751.     else
  752.         ODBlockMove(data, buffer, (size_t)size);
  753. }
  754.